package com.leyou.search.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.pojo.*;
import com.leyou.search.client.BrandClient;
import com.leyou.search.client.CategoryClient;
import com.leyou.search.client.GoodsClient;
import com.leyou.search.client.SpecificationClient;
import com.leyou.search.pojo.Goods;
import com.leyou.search.pojo.SearchRequest;
import com.leyou.search.pojo.SearchResult;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.utils.ChooseSegmentUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class IndexService {

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private SpecificationClient specificationClient;

    @Autowired
    private GoodsRepository goodsRepository;

    //查询spu的所有信息 来构建goods  以便存入索引库
    public Goods buildGoods(SpuBo spuBo) {
        //先获得spu商品的id，以便查询其他相关信息
        Long spuid = spuBo.getId();

        //商品分类的名称
        List<String> nameList = categoryClient.queryNameByIds(Arrays.asList(spuBo.getCid1(), spuBo.getCid2(), spuBo.getCid3()));
        String all = spuBo.getTitle() + " " + StringUtils.join(nameList, " ");

        //sku集合
        List<Sku> skus = goodsClient.querySkuBySpuId(spuid);
        //处理skus，将价格单独列出来，以便展示使用,其他sku信息存放到一个集合中
        List<Long> prices = new ArrayList<>();
        List<Map<String, Object>> skuList = new ArrayList<>();

        for (Sku sku : skus) {
            prices.add(sku.getPrice());
            //定义一个map集合，将每个sku的信息存放起来
            Map<String, Object> skumap = new HashMap<>();
            skumap.put("id", sku.getId());
            skumap.put("title", sku.getTitle());
            //展示的图片为第一张
            skumap.put("images", StringUtils.isBlank(sku.getImages()) ? "" : sku.getImages().split(",")[0]);
            skumap.put("prices", sku.getPrice());
            skuList.add(skumap);
        }

        //查询spudetail
        SpuDetail spuDetail = goodsClient.querySpuDetailById(spuid);
        //查询分类对应的规格参数 根据分类id和可被搜索进行查询
        List<SpecParam> params = specificationClient.querySpecParam(null, spuBo.getCid3(), true, null);
        //通用规格参数的值，通过工具类将json格式的参数转换成map进行存储
        Map<Long, String> genericSpec = JsonUtils.parseMap(spuDetail.getGenericSpec(), Long.class, String.class);
        //特有规格参数的值，通过工具类将json格式的参数转换成map进行存储
        Map<Long, List<String>> specialSpec = JsonUtils.nativeRead(spuDetail.getSpecialSpec(), new TypeReference<Map<Long, List<String>>>() {
        });
        //处理规格参数的显示问题，默认是显示id的值，处理成显示其对应的名称
        Map<String, Object> specs = new HashMap<>();
        for (SpecParam param : params) {
            Long paramId = param.getId();
            String paramName = param.getName();
            //定义一个变量，接收规格参数id对应的值
            Object value = null;
            if (param.getGeneric()) {
                //通用规格参数
                value = genericSpec.get(paramId);
                //若参数是数值类型的，则需额外进行处理，选定其范围
                if (param.getNumeric()) {
                    value = ChooseSegmentUtil.chooseSegment(value.toString(), param);
                }
            } else {
                //特有规格参数
                value = specialSpec.get(paramId);
            }
            if (null == value) {
                value = "";
            }
            specs.put(paramName, value);
        }

        //将数据都添加到goods对象中
        Goods goods = new Goods();
        goods.setId(spuid);
        goods.setAll(all);
        goods.setSubTitle(spuBo.getSubTitle());
        goods.setBrandId(spuBo.getBrandId());
        goods.setCid1(spuBo.getCid1());
        goods.setCid2(spuBo.getCid2());
        goods.setCid3(spuBo.getCid3());
        goods.setCreateTime(spuBo.getCreateTime());
        goods.setPrice(prices);
        goods.setSkus(JsonUtils.serialize(skuList));//将skus信息序列化成json字符串
        goods.setSpecs(specs);

        return goods;
    }

    //创建索引
    public void createIndex(Long id) {
        //根据spuid查询spu的信息
        Spu spu = this.goodsClient.querySpuById(id);
        //将spu的属性信息拷贝给spuBo
        SpuBo spuBo = new SpuBo();
        BeanUtils.copyProperties(spu,spuBo);
        //调用本类中的buildGoods方法，来对索引库进行操作
        Goods goods = this.buildGoods(spuBo);
        //将数据更新至索引库
        this.goodsRepository.save(goods);
    }
    //删除索引
    public void deleteIndex(Long id) {
        this.goodsRepository.deleteById(id);
    }
}
